/**
 * @author hAmmeRoL, created: 2008-7-9
 * SJTU
 */

package gui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import protocol.generic.AbstractProtocolManager;
import protocol.generic.ProtocolException;
import protocol.domain.Status;
import protocol.generic.Group;
import protocol.domain.GroupEntry;
import protocol.domain.InstantMessage;
import protocol.domain.UserPresence;

import com.trolltech.qt.QVariant;
import com.trolltech.qt.core.*;
import com.trolltech.qt.gui.QIcon;
import com.trolltech.qt.core.QMimeData;
import com.trolltech.qt.gui.QPixmap;
import com.trolltech.qt.gui.QTreeModel;

/**
 * Class representing all the entries in the list
 * 
 * @author hAmmeRoL
 * 
 */
public class BuddyList extends QTreeModel {

	// all the group entries
	ArrayList<Group> groupList;
	private HashMap<GroupEntry, ChatWindow> entryToChatWin;
	private HashMap<GroupEntry, AbstractProtocolManager> entryToManager;
	private HashMap<GroupEntry, QPixmap> entryToAvatar;
	MainWindow mw;
	
	public BuddyList(MainWindow parent) {
		super(parent);
		this.mw=parent;
		groupList = new ArrayList<Group>();
		entryToChatWin = new HashMap<GroupEntry, ChatWindow>();
		entryToManager = new HashMap<GroupEntry, AbstractProtocolManager>();
		entryToAvatar=new HashMap<GroupEntry, QPixmap>();
	}
	
	public void clear(){
		this.groupList.clear();
		this.entryToChatWin.clear();
		this.entryToManager.clear();
		entryToAvatar.clear();
	}
	
	/**
	 * get the ProtocolManager according to the GroupEntry
	 * @param ge
	 * 			the GroupEntry which you want to get its manager 
	 * @return the protocolManager which the ge belongs to
	 */
	public AbstractProtocolManager getManagerByEntry(GroupEntry ge){
		return entryToManager.get(ge);
	}
	
	/**
	 * get the Avatar according to the GroupEntry
	 * @param ge
	 * 			the GroupEntry which you want to get its Avatar pixmap 
	 * @return the Avatar pixmap which the ge belongs to
	 */
	public QPixmap getPixmapByEntry(GroupEntry ge){
		return entryToAvatar.get(ge);
	}

	/**
	 * Combine a new group into his group list
	 * 
	 * @param newGroupList
	 *            the new group list to combine
	 */
	public void addGroupList(AbstractProtocolManager manager,
			ArrayList<Group> newGroupList) {
		for (int i = 0; i < newGroupList.size(); i++) {
			Group newGroup = newGroupList.get(i);
			if (groupList.contains(newGroup)) {
				Group group = groupList.get(groupList.indexOf(newGroup));
				group.combineGroup(newGroup);
			} else {
				Group tempGroup=new Group(newGroup.getName());
				tempGroup.combineGroup(newGroup);
				groupList.add(tempGroup);
			}

			for (int j = 0; j < newGroup.getNum(); j++) {
				GroupEntry entry=newGroup.getGroupEntryByIndex(j);
				entryToManager.put(entry, manager);
				
				//add avatar to hashmap
				QPixmap pixmap=new QPixmap();
				try {
					pixmap.loadFromData(manager.getAvatar(entry.getID()));
				} catch (Exception e) {
					pixmap=new QPixmap("classpath:resources/send.png");
				}
				if(entry.getPresence().getStatus().equals(Status.UNAVAILABLE))
					entryToAvatar.put(entry, new QIcon(pixmap).pixmap(22, 22, QIcon.Mode.Disabled, QIcon.State.On));
				else
					entryToAvatar.put(entry, new QIcon(pixmap).pixmap(22, 22));
			}
		}
	}

	/**
	 * Get the group entry by its id
	 * 
	 * @param id
	 *            the id of the entry
	 * @return the group entry with the id of null if nothing is found
	 */
	public GroupEntry getGroupEntryByID(String id) {
		GroupEntry entry = null;
		for (Group group : groupList) {
			entry = group.getGroupEntryByID(id);
			if (entry != null) {
				return entry;
			}
		}

		return null;
	}

	/**
	 * Open the chat window associated with this entry
	 * 
	 * @param entry
	 *            the entry of the window to open
	 */
	public void openChatWindow(GroupEntry entry) {
		ChatWindow window = entryToChatWin.get(entry);
		AbstractProtocolManager manager = entryToManager.get(entry);

		// window not initialized
		if (window == null) {
			window = new ChatWindow(mw,entry, manager);
			entryToChatWin.put(entry, window);
			window.chatWindowClosed.connect(this, "disposeChatWindow(GroupEntry)");
		}
	}

	/**
	 * Process incoming message
	 * 
	 * @param message
	 *            the message
	 */
	public void processIncomingMessage(InstantMessage message) {
		String id = message.getFromID();
		GroupEntry entry = getGroupEntryByID(id);
		ChatWindow window = entryToChatWin.get(entry);
		AbstractProtocolManager manager = entryToManager.get(entry);
		
		if (window == null) {
			window = new ChatWindow(mw,entry, manager);
			entryToChatWin.put(entry, window);
			window.chatWindowClosed.connect(this, "disposeChatWindow(GroupEntry)");
		}
		window.displayReceivedMessage(message.getContent());
		System.out.println(this.entryToChatWin.size());
	}

	/**
	 * Update presence in the buddy list
	 * 
	 * @param presence
	 */
	public void updatePresence(UserPresence presence) {
		// find the entry
		for (Group group : groupList) {
			GroupEntry entry = group.getGroupEntryByID(presence.getUserID()
					.split("/")[0]);
			if (entry != null) {
				entry.setPresence(presence);
				
				// change the avatar hashmap
				QPixmap pixmap=new QPixmap();
				try {
					pixmap.loadFromData(entryToManager.get(entry).getAvatar(entry.getID()));
				} catch (Exception e) {
					pixmap=new QPixmap("classpath:resources/send.png");
				}
				if(entry.getPresence().getStatus().equals(Status.UNAVAILABLE))
					entryToAvatar.put(entry, new QIcon(pixmap).pixmap(22, 22, QIcon.Mode.Disabled, QIcon.State.On));
				else
					entryToAvatar.put(entry, new QIcon(pixmap).pixmap(22, 22));
				
				// change sequence
				group.update();
				this.layoutChanged.emit();
				this.mw.ui.treeView.expandAll();
			}
		}
	}

	/**
	 * Dispose the chat window of this entry, remove from the hash map
	 * 
	 * @param entry
	 *            the entry of the window to be disposed
	 */
	public void disposeChatWindow(GroupEntry entry) {
		ChatWindow window = entryToChatWin.get(entry);
		entryToChatWin.remove(entry);
		window.dispose();
	}

	@Override
	public Object child(Object arg0, int arg1) {
		if (arg0 == null) {
			return groupList.get(arg1);
		} else {
			return ((Group) (arg0)).getGroupEntryByIndex(arg1);
		}
	}

	@Override
	public int childCount(Object arg0) {
		// TODO Auto-generated method stub
		if (arg0 == null) {
			return groupList.size();
		} else if (arg0 instanceof Group) {
			return ((Group) (arg0)).getNum();
		} else {
			return 0;
		}
	}

	@Override
	public String text(Object arg0) {
		// TODO Auto-generated method stub
		if (arg0 instanceof Group) {
			return ((Group) (arg0)).getName();
		} else {
			/*
			 * 1.user Alias
			 * 2.user Status
			 * 3.Protocol
			 * 4.user ID
			 * 5.is blocked
			 */
			return ((GroupEntry) (arg0)).getAlias()+"#"+((GroupEntry) (arg0)).getPresence().getStatus().toString().toLowerCase()+"#"+this.entryToManager.get(arg0).getProtocol()+"#"+((GroupEntry) (arg0)).getID()+"#"+this.entryToManager.get(arg0).isBlocked(((GroupEntry) (arg0)).getID());
		}

	}

	/**
	 * Return status icon
	 */
	@Override
	public QIcon icon(Object value) {
		// default
		QPixmap pixmap = new QPixmap("classpath:resources/offline.png");
		if (value instanceof Group) {
			return new QIcon(new QPixmap("classpath:resources/person.png"));
		} else if (value instanceof GroupEntry) {
			GroupEntry entry = (GroupEntry) value;
			Status status = entry.getPresence().getStatus();

			if (status != Status.UNAVAILABLE) {
				pixmap = new QPixmap("classpath:resources/available.png");
			}

			return new QIcon(pixmap);
		}
		return null;
	}
	
	
	
	
	
	@Override
	public Qt.DropActions supportedDropActions(){
		return new Qt.DropActions(Qt.DropAction.CopyAction, Qt.DropAction.MoveAction);
	}
	
	
	@Override
	public boolean removeRows(int row, int count, QModelIndex parent){
		System.out.println("Removing from");

		if(parent!=null){
			System.out.println((String)parent.data(0));
			System.out.println((String)parent.child(row, 0).data(0));
			for(Group group : groupList){
				if(group.getName().equalsIgnoreCase((String)parent.data(0))){
					for(int i=count-1;i>=0;i--){
//						AbstractProtocolManager manager=this.getManagerByEntry(this.getGroupEntryByID(((String)parent.child(row+i, 0).data(0)).split("#")[3]));
						group.removeGroupEntryByID(((String)parent.child(row+i, 0).data(0)).split("#")[3]);
					}
				}
			}
		}
		this.layoutChanged.emit();
		this.mw.ui.treeView.expandAll();
		return true;
	}
	
	@Override
	public boolean insertRows(int row, int count, QModelIndex parent){
		return true;
	}
	
	@Override
	public java.util.List<String> mimeTypes(){
		System.out.println("Calling the mimeTypes");
		List<String> types=new ArrayList<String>();
		types.add("application/vnd.text.list");
		return types;
	 }
	
	@Override
	public QMimeData mimeData(List<QModelIndex> indexes){
		System.out.println("Calling the mimeData");
		QMimeData mimeData = new QMimeData();
		QByteArray encodedData=new QByteArray();

		QDataStream stream=new QDataStream(encodedData, QIODevice.OpenModeFlag.WriteOnly);

		for(QModelIndex index : indexes) {
			if (index!=null) {
				String text = data(index,0).toString();
				stream.writeString(text);
			}
		}
		mimeData.setData("application/vnd.text.list", encodedData);
		return mimeData;
	}
	
	@Override
	public boolean dropMimeData(QMimeData data,Qt.DropAction action,int row,int column,QModelIndex parent){
		if (action == Qt.DropAction.IgnoreAction)
			return true;
		if (!data.hasFormat("application/vnd.text.list"))
			return false;
		if (column > 0){
			System.out.println("column > 0");
			return false;
		}
		
		if(parent.parent()!=null)
			parent=parent.parent();

		int beginRow;
		if (row != -1)
			beginRow = row;
		else if (parent!=null)
			beginRow = parent.row();
		else
			beginRow = rowCount(parent);
		
		
		
		QByteArray encodedData = data.data("application/vnd.text.list");
		QDataStream stream=new QDataStream(encodedData, QIODevice.OpenModeFlag.ReadOnly);
		List<String> newItems=new ArrayList<String>();
		int rows = 0;

		while (!stream.atEnd()) {
			String text=stream.readString();
			newItems.add(text);
			++rows;
		}
		
		for(Group group : groupList){
			if(group.getName().equalsIgnoreCase((String)parent.data(0))){
				System.out.println("(String)parent.data(0)	"+(String)parent.data(0));
				for(String s : newItems){
					group.addGroupEntry(this.getGroupEntryByID(s.split("#")[3]));
					
					AbstractProtocolManager manager=this.getManagerByEntry(this.getGroupEntryByID(s.split("#")[3]));
					ArrayList<Group> tempGroups=manager.getGroups();
					String oldGroupName="";
					String newGroupName="";
					for(Group tempGroup : tempGroups){
						if(tempGroup.getGroupEntryByID(s.split("#")[3])!=null)
							oldGroupName=tempGroup.getName();
						if(tempGroup.getName().equalsIgnoreCase(group.getName()))
							newGroupName=group.getName();
					}
					if(newGroupName.equalsIgnoreCase("")){
						System.out.println("Creating group!!!!");
						manager.createGroup(group.getName());
						newGroupName=group.getName();
					}
					try {
						System.out.println("oldGroupName	"+oldGroupName);
						System.out.println("newGroupName	"+newGroupName);
						System.out.println("ID	"+s.split("#")[3]);
						manager.moveEntryToGroup(oldGroupName, s.split("#")[3], newGroupName);
					} catch (ProtocolException e) {
						e.printStackTrace();
					}
					
					System.out.println("inserting+++++"+s.split("#")[3]);
				}
			}
		}
		return true;
	}
	
	
	
	@Override
	public boolean setData(QModelIndex index,Object value,int role){
		System.out.println("Calling the setData");
		return false;
	}
	
	
	@Override
	public Qt.ItemFlags flags(QModelIndex index){
		return new Qt.ItemFlags(Qt.ItemFlag.ItemIsDragEnabled.value() | Qt.ItemFlag.ItemIsDropEnabled.value() | Qt.ItemFlag.ItemIsSelectable.value());
	}
	
	
}
